home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
ab20
/
ab20_archive
/
utilities
/
emulators
/
spectrum_readplusd.lzh
/
ReadPlusD.mod
< prev
Wrap
Text File
|
1991-04-25
|
13KB
|
462 lines
MODULE ReadPlusD;
(*
This file may be distributed anywhere provided it is unmodified and is not
sold for profit. Please report bugs to the author.
Author: Peter McGavin, 86 Totara Crescent, Lower Hutt, New Zealand.
e-mail: srwmpnm@wnv.dsir.govt.nz .
This Benchmark Modula-2 program reads an MGT (Miles Gordon Technology) PLUS D
3.5" double-sided diskette on any Amiga. MGT PLUS D diskettes are used on
Sinclair Spectrum computers. This is useful for transferring Spectrum programs
to the format required by the Spectrum emulator on the Amiga.
ReadPlusD requires messydisk.device (supplied with MSH on Fred Fish disk 382)
in the devs: directory.
CLI usage: ReadPlusD disk-unit-number [directory-entry-number output-file]
The disk unit number should be an integer in the range 0..3 corresponding to
the drive (DF0:..DF3:) containing the PLUS D diskette.
If given just the unit-number, ReadPlusD displays a directory of the disk.
If you also give a directory entry number and an output file name, ReadPlusD
converts a 48 kbyte snapshot file to the format required by the Amiga Spectrum
emulator. The output is written to the given file name.
Note that you specify the number of the directory entry (an integer in the
range 1..80), not the name of the input file. If the file is not a 48 kbyte
snapshot file, ReadPlusD displays an error message.
Examples:
ReadPlusD 2 get a directory of the PLUS D disk in DF2:
ReadPlusD 1 17 RAM:TRON convert the 17th file on DF1: to RAM:TRON
Known bug:
ReadPlusD always sets the z80 interrupt mode to 1. A few Spectrum programs use
interrupt mode 2. If a converted program doesn't run and you suspect it might
use mode 2, try patching the byte at offset 25 in the output file to be $02.
Use a binary file editor like, for example, NEWZAP. The byte you patch is
actually the 26th byte in the file (because the 1st byte is at offset 0), and
it will always be $01 to begin with.
If you know how to fix this bug, please tell me how to do it.
*)
FROM SYSTEM IMPORT ADR, ADDRESS, BYTE, LONGWORD;
FROM AmigaDOS IMPORT FileHandle, ModeNewFile, Open, Write, Close;
FROM Conversions IMPORT ConvStringToNumber;
FROM InOut IMPORT WriteLn, WriteString, WriteCard, Read;
FROM IODevices IMPORT OpenDevice, CloseDevice, DoIO, CmdRead;
FROM IODevicesUtil IMPORT CreateExtIO, DeleteExtIO;
FROM Memory IMPORT AllocMem, FreeMem, MemReqSet, MemPublic, MemClear;
FROM Ports IMPORT MsgPortPtr, GetMsg, PutMsg, WaitPort;
FROM PortsUtil IMPORT CreatePort, DeletePort;
FROM Strings IMPORT ExtractSubString;
FROM System IMPORT argc, argv;
FROM TrackDiskDevice IMPORT IOExtTD, IOExtTDPtr, TDName, TDMotor;
CONST
MDName = "messydisk.device";
NumSecs = 10;
VAR
buffer: ARRAY [0..511] OF BYTE;
PROCEDURE motor (diskreq: IOExtTDPtr; onoff: BOOLEAN);
VAR
dummy: LONGINT;
BEGIN
WITH diskreq^.iotdReq DO
IF onoff THEN
ioLength := 1D
ELSE
ioLength := 0D
END;
ioCommand := TDMotor
END;
dummy := DoIO (diskreq)
END motor;
PROCEDURE read_sector (diskreq: IOExtTDPtr;
sector: CARDINAL;
bufptr: ADDRESS): CARDINAL;
VAR
dummy: LONGINT;
BEGIN
WITH diskreq^.iotdReq DO
ioLength := 512D;
ioData := bufptr;
ioOffset := 512D * LONGCARD(sector);
ioCommand := CmdRead;
dummy := DoIO (diskreq);
RETURN CARDINAL (ioError)
END
END read_sector;
PROCEDURE msh_sector (track, sector: CARDINAL): CARDINAL;
(* Convert from Plus-D track and sector number to messydisk sector number *)
BEGIN
IF track >= 128 THEN (* it's on the reverse side *)
RETURN 2 * NumSecs * (track - 128) + NumSecs + sector - 1
ELSE
RETURN 2 * NumSecs * track + sector - 1
END
END msh_sector;
TYPE
dir_entry_type = RECORD
CASE :INTEGER OF
0: c: ARRAY [0..255] OF CHAR |
1: b: ARRAY [0..255] OF BYTE
END;
END;
dir_entry_ptr_type = POINTER TO dir_entry_type;
PROCEDURE write_dir_entry (entry_number: CARDINAL;
dir_entry_ptr: dir_entry_ptr_type);
VAR
name: ARRAY [0..10] OF CHAR;
BEGIN
WITH dir_entry_ptr^ DO
IF CARDINAL(b[0]) <> 0 THEN
WriteCard (entry_number, 2);
WriteString (" ");
CASE CARDINAL(b[0]) OF
1: WriteString ("Basic program ") |
2: WriteString ("Numeric array ") |
3: WriteString ("Character array ") |
4: WriteString ("Code file ") |
5: WriteString ("48k snapshot ") |
7: WriteString ("Screen dump ") |
10:WriteString ("Open# file ")
ELSE
WriteString ("Type ");
WriteCard (CARDINAL(b[0]), 2);
WriteString (" ")
END;
ExtractSubString (name, c, 1, 10);
WriteString (name);
WriteCard (CARDINAL(b[12]), 6); (* size *)
(*
WriteCard (CARDINAL(b[13]), 4); (* starting track *)
WriteCard (CARDINAL(b[14]), 4); (* starting sector *)
*)
WriteLn
END
END
END write_dir_entry;
PROCEDURE directory (diskreq: IOExtTDPtr): BOOLEAN;
VAR
track,
sector,
entry_number: CARDINAL;
BEGIN
entry_number := 0;
FOR track := 0 TO 3 DO
FOR sector := 1 TO 10 DO
IF read_sector (diskreq, msh_sector (track, sector), ADR(buffer)) <> 0 THEN
WriteString ("Error reading sector\n");
RETURN FALSE
END;
INC (entry_number);
write_dir_entry (entry_number, ADR(buffer[0]));
INC (entry_number);
write_dir_entry (entry_number, ADR(buffer[256]))
END
END;
RETURN TRUE
END directory;
PROCEDURE convert_snapshot (entry_number: CARDINAL;
filename: ARRAY OF CHAR;
diskreq: IOExtTDPtr): BOOLEAN;
CONST
image_size = 49179D;
image_buffer_size = image_size + 512D;
VAR
track,
sector,
sp: CARDINAL;
z80_address,
tmp: LONGCARD;
ok: BOOLEAN;
image: POINTER TO ARRAY [0..27] OF BYTE; (* really 49179 byte buffer *)
image_ptr: POINTER TO ARRAY [0..511] OF BYTE;
dir_entry_ptr: dir_entry_ptr_type;
file: FileHandle;
BEGIN
ok := TRUE;
image := NIL;
file := NIL;
IF (entry_number <= 0) OR (entry_number > 80) THEN
WriteString ("Entry number is out of range\n");
ok := FALSE
END;
DEC (entry_number); (* now in range 0..79 *)
IF ok THEN
track := entry_number DIV 20;
sector := (entry_number MOD 20) DIV 2 + 1;
IF read_sector (diskreq, msh_sector (track, sector), ADR(buffer)) <> 0 THEN
WriteString ("Error reading sector\n");
ok := FALSE
END
END;
IF ok THEN
IF ODD(entry_number) THEN
dir_entry_ptr := ADR(buffer[256])
ELSE
dir_entry_ptr := ADR(buffer[0])
END;
WITH dir_entry_ptr^ DO
IF CARDINAL(b[0]) <> 5 THEN
WriteString ("Error, entry number ");
WriteCard (entry_number + 1, 2);
WriteString (" is not a 48k snapshot file\n");
ok := FALSE
END
END
END;
IF ok THEN
image := AllocMem (image_buffer_size, MemReqSet{});
IF image = NIL THEN
WriteString ("Can't allocate image buffer\n");
ok := FALSE
END
END;
IF ok THEN
sp := 256 * CARDINAL(dir_entry_ptr^.b[0F1H]) + CARDINAL(dir_entry_ptr^.b[0F0H]);
INC (sp, 4);
image^[ 0] := dir_entry_ptr^.b[0EFH]; (* i *)
image^[ 1] := dir_entry_ptr^.b[0E4H]; (* l' *)
image^[ 2] := dir_entry_ptr^.b[0E5H]; (* h' *)
image^[ 3] := dir_entry_ptr^.b[0E0H]; (* e' *)
image^[ 4] := dir_entry_ptr^.b[0E1H]; (* d' *)
image^[ 5] := dir_entry_ptr^.b[0E2H]; (* c' *)
image^[ 6] := dir_entry_ptr^.b[0E3H]; (* b' *)
image^[ 7] := dir_entry_ptr^.b[0E6H]; (* f' *)
image^[ 8] := dir_entry_ptr^.b[0E7H]; (* a' *)
image^[ 9] := dir_entry_ptr^.b[0ECH]; (* l *)
image^[10] := dir_entry_ptr^.b[0EDH]; (* h *)
image^[11] := dir_entry_ptr^.b[0E8H]; (* e *)
image^[12] := dir_entry_ptr^.b[0E9H]; (* d *)
image^[13] := dir_entry_ptr^.b[0EAH]; (* c *)
image^[14] := dir_entry_ptr^.b[0EBH]; (* b *)
image^[15] := dir_entry_ptr^.b[0DCH]; (* iyl *)
image^[16] := dir_entry_ptr^.b[0DDH]; (* iyh *)
image^[17] := dir_entry_ptr^.b[0DEH]; (* ixl *)
image^[18] := dir_entry_ptr^.b[0DFH]; (* ixh *)
image^[19] := dir_entry_ptr^.b[0EEH]; (* int *)
image^[20] := BYTE(00H); (* r *)
image^[21] := BYTE(00H); (* f filled in later *)
image^[22] := BYTE(00H); (* a filled in later *)
image^[23] := BYTE(sp MOD 256); (* spl *)
image^[24] := BYTE(sp DIV 256); (* sph *)
image^[25] := BYTE(1); (* im might be wrong!!! *)
image^[26] := BYTE(0); (* fill *)
track := CARDINAL(dir_entry_ptr^.b[00DH]);
sector := CARDINAL(dir_entry_ptr^.b[00EH]);
image_ptr := ADR(image^[27]);
z80_address := 16384D
END;
WHILE ok AND (track <> 0) AND (sector <> 0) DO
IF read_sector (diskreq, msh_sector (track, sector), image_ptr) <> 0 THEN
WriteString ("Error reading sector\n");
ok := FALSE
ELSE
tmp := LONGCARD(sp - 2);
IF (tmp >= z80_address) AND
(tmp < (z80_address + 510D)) THEN
image^[21] := image_ptr^[CARDINAL(tmp - z80_address)] (* f *)
END;
tmp := LONGCARD(sp - 1);
IF (tmp >= z80_address) AND
(tmp < (z80_address + 510D)) THEN
image^[22] := image_ptr^[CARDINAL(tmp - z80_address)] (* a *)
END;
track := CARDINAL(image_ptr^[510]);
sector := CARDINAL(image_ptr^[511]);
image_ptr := ADDRESS(LONGCARD(image_ptr) + 510D);
INC (z80_address, 510D)
END
END;
IF ok THEN
file := Open (ADR(filename), ModeNewFile);
IF file = NIL THEN
WriteString ("Error opening output file\n");
ok := FALSE
END
END;
IF ok THEN
IF Write (file, image, image_size) <> image_size THEN
WriteString ("Error writing output file\n");
ok := FALSE
END
END;
IF file <> NIL THEN
Close (file)
END;
IF image <> NIL THEN
FreeMem (image, image_buffer_size)
END;
RETURN ok
END convert_snapshot;
VAR
unit: CARDINAL;
diskport: MsgPortPtr;
diskreq: IOExtTDPtr;
devopen: LONGINT;
ok: BOOLEAN;
ch: CHAR;
entry_number: CARDINAL;
temp: LONGCARD;
BEGIN
ok := TRUE;
diskport := NIL;
diskreq := NIL;
devopen := -1D;
unit := 0;
entry_number := 0;
IF ok THEN
IF (argc <> 2) AND (argc <> 4) THEN
ok := FALSE
END
END;
IF ok THEN
IF argc >= 2 THEN
ok := ConvStringToNumber (argv^[1]^, temp, FALSE, 10);
IF ok THEN
unit := CARDINAL(temp);
ok := unit < 4
END;
IF NOT ok THEN
WriteString ("Disk unit must be a number in the range 0..3\n")
END
END
END;
IF ok THEN
IF argc >= 3 THEN
ok := ConvStringToNumber (argv^[2]^, temp, FALSE, 10);
IF ok THEN
entry_number := CARDINAL(temp);
ok := (entry_number > 0) AND (entry_number <= 80)
END;
IF NOT ok THEN
WriteString ("Entry number must be a number in the range 1..80\n")
END
END
END;
IF NOT ok THEN
WriteString ("Usage: ReadPlusD disk-unit-number [entry-number output-file]\n");
END;
IF ok THEN
diskport := CreatePort (NIL, 0);
IF diskport = NIL THEN
WriteString ("Can't create message port\n");
ok := FALSE
END
END;
IF ok THEN
diskreq := CreateExtIO (diskport^, SIZE(IOExtTD));
IF diskreq = NIL THEN
WriteString ("Can't create external IO request\n");
ok := FALSE
END
END;
IF ok THEN
devopen := OpenDevice (ADR(MDName), unit, diskreq, 0D);
IF devopen <> 0D THEN
WriteString ("Can't open devs:messydisk.device on unit ");
WriteCard (unit, 1);
WriteLn;
ok := FALSE
END
END;
IF ok THEN (* must read sector 0 first to discover number of sectors/track *)
ok := read_sector (diskreq, 0, ADR(buffer)) = 0;
IF NOT ok THEN
WriteString ("Error reading sector\n")
END
END;
IF ok THEN
IF entry_number = 0 THEN
ok := directory (diskreq)
END
END;
IF ok THEN
IF entry_number <> 0 THEN
WriteString ("\nConverting entry ");
WriteCard (entry_number, 1);
WriteString (" to ");
WriteString (argv^[3]^);
WriteLn;
ok := convert_snapshot (entry_number, argv^[3]^, diskreq)
END
END;
IF devopen = 0D THEN
motor (diskreq, FALSE);
CloseDevice (diskreq);
devopen := -1D
END;
IF diskreq <> NIL THEN
DeleteExtIO (diskreq);
diskreq := NIL
END;
IF diskport <> NIL THEN
DeletePort (diskport^);
diskport := NIL
END
END ReadPlusD.